package cn.sh.basic.service.impl;

import cn.sh.basic.constant.WechatConstant;
import cn.sh.basic.domain.dto.LoginDto;
import cn.sh.basic.domain.dto.WxBinderDto;
import cn.sh.basic.exception.CustomException;
import cn.sh.basic.jwt.JwtUtils;
import cn.sh.basic.jwt.RsaUtils;
import cn.sh.basic.jwt.UserInfo;
import cn.sh.basic.service.ILoginService;
import cn.sh.basic.util.AjaxResult;
import cn.sh.basic.util.HttpClientUtils;
import cn.sh.basic.util.MD5Utils;
import cn.sh.basic.util.StrUtils;
import cn.sh.system.domain.Menu;
import cn.sh.system.mapper.MenuMapper;
import cn.sh.system.mapper.PermissionMapper;
import cn.sh.user.domain.Logininfo;
import cn.sh.user.domain.User;
import cn.sh.user.domain.Wxuser;
import cn.sh.user.mapper.LogininfoMapper;
import cn.sh.user.mapper.UserMapper;
import cn.sh.user.mapper.WxuserMapper;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.security.PrivateKey;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
public class LoginServiceImpl implements ILoginService {

    @Autowired
    private LogininfoMapper logininfoMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private WxuserMapper wxuserMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private MenuMapper menuMapper;

    @Autowired
    private PermissionMapper permissionMapper;


    @Override
    public Object accountLogin(LoginDto dto) throws Exception {
        //非空校验
        if(StringUtils.isEmpty(dto.getUsername()) || StringUtils.isEmpty(dto.getPassword())){
            throw new CustomException("参数异常");
        }
        //查询是否有这个用户
        Logininfo logininfo = logininfoMapper.queryByUserNameAndType(dto.getUsername(),dto.getType());

        if(logininfo == null){
            throw new CustomException("该用户不存在");
        }
        //通过传进来的密码进行加密后和查询出来的密码比对
        String newPassword = MD5Utils.encrypByMd5(dto.getPassword() + logininfo.getSalt());

        if(!logininfo.getPassword().equals(newPassword)){
            throw new CustomException("用户名或密码错误");
        }
//        //生成UUID存储到redis，key是uuid，value是loginInfo对象，过期时间30分钟
//        String token = UUID.randomUUID().toString();
//
//        redisTemplate.opsForValue().set(token,logininfo,30, TimeUnit.MINUTES);
//        //返回给前端，UUID，loginInfo
//        Map<String, Object> map = new HashMap<>();
//        map.put("token",token);
//        logininfo.setSalt(null);
//        logininfo.setPassword(null);
//        map.put("logininfo",logininfo);
        return loginSuccessHandler(logininfo);
    }

    private Map<String, Object> loginSuccessHandler(Logininfo logininfo) throws Exception {
        UserInfo userInfo = new UserInfo();
        //存放登录信息
        userInfo.setLogininfo(logininfo);
        //判断登录用户是员工还是主站用户
        if(logininfo.getType() == 1){
            userInfo.setMenus(null);
            userInfo.setPermissions(null);
        }else{
            //获取用户对应的menus
            List<Menu> menus =  menuMapper.queryOwnMenusByLoginInfoId(logininfo.getId());
            //获取用户对应的permissions
            List<String> permissions = permissionMapper.ownSn(logininfo.getId());
            userInfo.setMenus(menus);
            userInfo.setPermissions(permissions);
        }
        //加密jwttoken
        PrivateKey privateKey = RsaUtils.getPrivateKey(JwtUtils.class.getClassLoader().getResource("hrm_auth_rsa").getFile());
        String token = JwtUtils.generateTokenExpireInMinutes(userInfo, privateKey, 24*60);
        //返回前端，还是返回map（logininfo,menus,permissions）
        Map<String,Object> map = new HashMap<>();
        map.put("token",token);
        userInfo.getLogininfo().setSalt(null);
        userInfo.getLogininfo().setPassword(null);
        map.put("logininfo", userInfo.getLogininfo());
        map.put("menus",userInfo.getMenus());
        map.put("permissions",userInfo.getPermissions());
        return map;
    }

    @Override
    public AjaxResult wechat(Map<String, String> map) throws Exception{
        //获取code
        String code = map.get("code");
        //空参数校验
        if(code == null){
            throw new CustomException("参数异常");
        }
        //拿到获取token的接口url
        String getTokenUrl = WechatConstant.GET_TOKEN_URL
                .replace("APPID",WechatConstant.APPID)
                .replace("CODE",code)
                .replace("SECRET",WechatConstant.SECRET);

        //请求wx服务器，result就是响应内容
        String result = HttpClientUtils.httpGet(getTokenUrl);
        //把响应结果转换成json对象
        JSONObject jo = JSONObject.parseObject(result);
        //从json对象中获取token和openid
        String token = jo.getString("access_token");
        String openid = jo.getString("openid");
        //通过openid查询该用户是否已经存在
        Wxuser wxuser = wxuserMapper.queryByOpenId(openid);
        if(wxuser != null){
            //通过wxuser的userid查询logininfo
            Logininfo logininfo = logininfoMapper.queryByUserId(wxuser.getUserId());
            //判断loginInfo是否存在
            if(logininfo == null){
                throw new CustomException("数据异常");
            }
//            //生成UUID存储到redis，key是uuid，value是loginInfo对象，过期时间30分钟
//            String redisToken = UUID.randomUUID().toString();
//            redisTemplate.opsForValue().set(redisToken,logininfo,30, TimeUnit.MINUTES);
//            //返回给前端，UUID，loginInfo
//            Map<String, Object> mapResult = new HashMap<>();
//            mapResult.put("token",redisToken);
//            logininfo.setSalt(null);
//            logininfo.setPassword(null);
//            mapResult.put("logininfo",logininfo);
            return AjaxResult.me().setResultObj(loginSuccessHandler(logininfo));
        }
        //http://127.0.0.1/binder.html?token=xxxxx&openid=xxxxx
        String binderUrl = "?token="+token+"&openid="+openid;
        return AjaxResult.me().setSuccess(false).setResultObj(binderUrl);
    }

    @Override
    public AjaxResult binder(WxBinderDto dto) throws Exception {
        //空参数校验
        if(StringUtils.isEmpty(dto.getAccessToken()) ||
                StringUtils.isEmpty(dto.getOpenId())||
                StringUtils.isEmpty(dto.getPassword())||
                StringUtils.isEmpty(dto.getPhone())){
            throw new CustomException("参数异常");
        }
        //拿到获取微信用户基本信息的接口地址
        String url = WechatConstant.GET_INFO_URL
                .replace("ACCESS_TOKEN",dto.getAccessToken())
                .replace("OPENID",dto.getOpenId());
        //获取用户微信基本信息json字符串
        String result = HttpClientUtils.httpGet(url);
        //把用户微信基本信息json字符串转换成json对象
        JSONObject jo = JSONObject.parseObject(result);
        //初始化wxuser对象
        Wxuser wxuser = initWxUser(jo);

        //查询用户是否已经通过网站注册过
        Logininfo logininfo = logininfoMapper.queryByUserNameAndType(dto.getPhone(), 1);
        //如果注册过
        if(logininfo != null){
            //查询该loginInfo对应的user
            User user = userMapper.queryByUserName(dto.getPhone());
            wxuser.setUserId(user.getId());
            wxuserMapper.add(wxuser);
        }else{
            //生成盐值
            String salt = StrUtils.getComplexRandomString(32);
//        使用MD5工具类加密密码（密码需要拼接盐值一起加密）
            String md5PassWord = MD5Utils.encrypByMd5(dto.getPassword() + salt);
            User user = initUser(dto.getPhone(),salt,md5PassWord);
            logininfo =  user2LoginInfo(user);
//        8. 先保存login_info，获取自增id
            logininfoMapper.add(logininfo);
            //把logininfo保存后的自增id给到user中
            user.setLogininfoId(logininfo.getId());
            //        9. 再保存user
            userMapper.add(user);
            //更新wxuser的userid
            wxuser.setUserId(user.getId());
            //保存wxuser
            wxuserMapper.add(wxuser);
        }
        //生成UUID存储到redis，key是uuid，value是loginInfo对象，过期时间30分钟
//        String redisToken = UUID.randomUUID().toString();
//        redisTemplate.opsForValue().set(redisToken,logininfo,30, TimeUnit.MINUTES);
//        //返回给前端，UUID，loginInfo
//        Map<String, Object> mapResult = new HashMap<>();
//        mapResult.put("token",redisToken);
//        logininfo.setSalt(null);
//        logininfo.setPassword(null);
//        mapResult.put("logininfo",logininfo);
        return AjaxResult.me().setResultObj(loginSuccessHandler(logininfo));
    }

    private Wxuser initWxUser(JSONObject jo) {
        Wxuser wxuser = new Wxuser();
        wxuser.setAddress(jo.getString("country"));
        wxuser.setHeadimgurl(jo.getString("headimgurl"));
        wxuser.setNickname(jo.getString("nickname"));
        wxuser.setOpenid(jo.getString("openid"));
        wxuser.setUnionid(jo.getString("unionid"));
        wxuser.setSex(jo.getInteger("sex"));
        return wxuser;
    }

    private Logininfo user2LoginInfo(User user) {
        Logininfo logininfo = new Logininfo();
        BeanUtils.copyProperties(user,logininfo);
        //初始化参数type 1主站用户
        logininfo.setType(1);
        //初始化参数disabl 1 可用
        logininfo.setDisable(1);
        return logininfo;
    }

    private User initUser(String mobile, String salt, String md5PassWord) {
        User user = new User();
        user.setUsername(mobile);
        user.setPhone(mobile);
        user.setSalt(salt);
        user.setPassword(md5PassWord);
        user.setState(1);
        user.setCreatetime(new Date());
        return user;
    }
}
